Umsetzung ========= Gitea on Docker Compose mit PostgreSQL -------------------------------------- Zum Aufsetzen der Gitea-Instanz auf einem Docker-Host wird Docker Compose verwendet, um die Konfiguration und Bereitstellung von Gitea und PostgreSQL zu vereinfachen. Der Nginx Webserver wird nicht in Docker Compose konfiguriert, sondern in den nächsten Schritten manuell auf dem Host-System eingerichtet, inklusive Reverse-Proxy-Funktionalität. Folgendes Docker-Compose-Beispiel zeigt die Konfiguration von Gitea und PostgreSQL in getrennten Containern. .. code-block:: docker networks: gitea: external: false services: server: image: gitea/gitea:1.21.7 container_name: gitea environment: - USER_UID=1000 - USER_GID=1000 - GITEA__database__DB_TYPE=postgres - GITEA__database__HOST=db:5432 - GITEA__database__NAME=gitea - GITEA__database__USER=gitea - GITEA__database__PASSWD=*#+*4sv*sjmEWfY:U88D$$gRzFvSNE9;H restart: always networks: - gitea volumes: - ./gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "3000:3000" - "222:22" depends_on: - db db: image: postgres:14 restart: always environment: - POSTGRES_USER=gitea - POSTGRES_PASSWORD=*#+*4sv*sjmEWfY:U88D$$gRzFvSNE9;H - POSTGRES_DB=gitea networks: - gitea volumes: - ./postgres:/var/lib/postgresql/data Die finale und reproduzierbare Version ist in `Gitea/docker-compose.yml` abgelegt. Erklärung der Dockerfile-Konfiguration `````````````````````````````````````` Die Docker-Konfiguration umfasst die Einrichtung einer Gitea-Instanz und einer PostgreSQL-Datenbank in getrennten Containern innerhalb eines Docker-Netzwerks. Netzwerkkonfiguration ~~~~~~~~~~~~~~~~~~~~~ - Das Netzwerk ``gitea`` wird definiert und ist ausschließlich innerhalb der Docker-Umgebung sichtbar. - Über das isolierte Netzwerk können die Gitea- und PostgreSQL-Container miteinander kommunizieren. Servicekonfiguration ~~~~~~~~~~~~~~~~~~~~ Gitea-Service +++++++++++++ - Verwendet das offizielle Gitea-Image ``gitea/gitea:1.21.7``. - Setzt den Container-Namen auf ``gitea``. - Konfiguriert Gitea mit Umgebungsvariablen für Benutzer-IDs und Datenbankverbindungen. - Sorgt für den automatischen Neustart des Containers. - Verbindet den Service mit dem ``gitea`` Netzwerk. - Bindet Host-Verzeichnisse für persistente Daten und Systemzeit-Synchronisation. - Leitet Ports für Webinterface und SSH weiter. - Stellt die Abhängigkeit zum Datenbank-Service sicher. Datenbank-Service (PostgreSQL) ++++++++++++++++++++++++++++++ - Nutzt das PostgreSQL-Image ``postgres:14``. - Konfiguriert PostgreSQL mit Umgebungsvariablen für Benutzer, Passwort und Datenbank. - Bindet den Service an das ``gitea`` Netzwerk. - Speichert Datenbankdaten persist auf dem Host-System. Diese Konfiguration ermöglicht eine effiziente Einrichtung von Gitea und PostgreSQL in Docker, wobei die Portabilität und einfache Skalierung der Dienste im Vordergrund stehen. Let's Encrypt & CertBot ----------------------- Let's Encrypt ist eine Zertifizierungsstelle, die kostenlose SSL/TLS-Zertifikate ausstellt, um die Verschlüsselung von Websites zu fördern. Die CA stellt eine ACME (Automated Certificate Management Environment) API bereit, die von Tools wie Certbot genutzt wird, um Zertifikate automatisch zu erhalten und zu erneuern. Certbot ist ein Open-Source-Tool, das entwickelt wurde, um die Einrichtung von SSL-Zertifikaten zu vereinfachen und zu automatisieren. Installation ```````````` ``snap`` ........ ``snap`` ist ein Paket-Manager für Ubuntu und wird benötigt zum Installieren von ``certbot``. Mit dem simplen Befehl wird dieses installiert: .. code-block:: bash sudo apt install snapd Anschließend kann dieses getestet werden mittels: .. code-block:: bash sudo snap install hello-world ``certbot`` ........... Um ``certbot`` zu installieren nutzen wir den ``snap`` Paket-Manager: .. code-block:: bash sudo snap install --classic certbot Anschließend fügen wir die ausführbare Datei unserem Pfad hinzu um ``certbot`` von jeden Verzeichnis aus bequem aufrufen zu können: .. code-block:: bash sudo ln -s /snap/bin/certbot /usr/bin/certbot Der oben aufgeführte Befehl erstellt eine symbolische Verknüpfung zur ``certbot`` Datei. Dies bedeutet dass die Datei in ``/usr/bin/`` lediglich auf die Datei in ``/snap/bin/`` verweist und der eigentlich Aufruf dort erfolgt. Konfiguration ````````````` Zertifikate anfragen .................... Nun ist es möglich Zertifikate anzufragen. Dies geschieht über den Befehl: .. code-block:: bash sudo certbot --nginx Oder über diesen Befehl, wenn wir keine automatische Installation in Nginx wünschen: .. code-block:: bash sudo certbot certonly --nginx Automatische Erneuerung ....................... ``certbot`` legt automatisch einen ``cron`` Auftrag an, welche genutzt werden um Befehle zu einem bestimmten Zeitpunkt auszuführen wie "Jeden Tag um 08:00 Uhr". Dadurch kommt es zu keinen Fehlschlägen bei der SSL Verschlüsselung durch abgelaufene Zertifikate. Um diese Funktionalität zu testen ist folgender Befehl vorhanden: .. code-block:: bash sudo certbot renew --dry-run NGINX ----- Installation ```````````` Um ``nginx`` zu installieren sind ein paar Schritte nötig. Voraussetzungen ............... Um die benötigten Abhängigkeiten zu installieren nutzen wir folgenden Befehl: .. code-block:: bash sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring Repository .......... Um ``nginx`` aus der offiziellen Repository zu beziehen wird ein "Signing Key" benötigt, welcher die Authentifizierung der Datei bestätigt: .. code-block:: bash curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null .. code-block:: bash gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg Die Ausgabe sollte nun den folgenden Fingerabdruck beinhalten: .. code-block:: bash pub rsa2048 2011-08-19 [SC] [expires: 2024-06-14] 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 uid nginx signing key Nun können wir das Repository hinzufügen: .. code-block:: bash echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \ | sudo tee /etc/apt/sources.list.d/nginx.list Der letzte Schritt legt das hinzugefügte Repository als bevorzugtes Repository fest um zu verhindern dass ``nginx`` aus den Standard Repositories bezogen wird: .. code-block:: bash echo -e "Package: \*\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \ | sudo tee /etc/apt/preferences.d/99nginx Nun können wir ``nginx`` installieren: .. code-block:: bash sudo apt install nginx Konfiguration ````````````` Um die Reverse Proxy zu konfigurieren ist es nötig ins ``nginx`` Verzeichnis zu wechseln: .. code-block:: bash cd /etc/nginx/ Aus Organisationszwecken erstellen wir nun zwei Ordner im Verzeichnis: ``sites-available`` und ``sites-enabled`` .. code-block:: bash mkdir sites-available sites-enabled Im ersteren Ordner werden alle Konfigurationen aufbewahrt und sobald diese "aktiviert" werden sollen, werden diese mittels symbolischer Links verknüpft mit dem letzteren Ordner. Nun wird die Konfigurationsdatei für unseren Gitea Service erstellt im Ordner ``sites-enabled``: .. code-block:: bash cd sites-available sudo nano gitea.conf Innerhalber dieser Datei schreiben wir folgende Anweisungen an ``nginx``: .. code-block:: text server { listen 80 http2; listen 443 http2 ssl; server_name dva.mahart.ma; ssl_certificate /etc/letsencrypt/live/dva.mahart.ma/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/dva.mahart.ma/privkey.pem; # managed by Certbot location / { client_max_body_size 512M; proxy_set_header Connection $http_connection; proxy_set_header Upgrade $http_upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:3000$uri; } } Diese Konfigurationdatei drückt aus dass wir auf den Ports 80 und 443 auf Anfragen hören möchten, sowie dass wir HTTP2 und SSL für Port 443 unterstützen. Darauffolgend geben wir unsere Domain and und die Pfade zu unseren SSL Zertifikaten welche wir generiert haben. Im ``location /`` Tag können wir nun bestimmen was passiert wenn die Ressource unter dem Pfad ``/`` angefragt wird. Um Probleme mit Git Pushes zu vermeiden erlauben wir es dem Client größere Anfragen zu senden (512 MB), zudem setzen wir bestimmte Header innerhalb der Anfrage für die weitere Verarbeitung durch Gitea und leiten anschließend die Anfrage weiter and den internen Port 3000 auf welchem Gitea auf Anfragen wartet und diese weiterverarbeitet. Anschließend "aktivieren" wir diese Konfiguration mittels einer Verknüpfung: .. code-block:: bash sudo ln -s /etc/nginx/sites-available/gitea.conf /etc/nginx/sites-enabled/gitea.conf Damit diese Konfiguration auch von ``nginx`` beachtet wird, fügen wir sie und alle zukünftigen Konfigurationen der Hauptkonfigurationsdatei unter ``/etc/nginx/nginx.conf`` hinzu: .. code-block:: bash cd /etc/nginx/ sudo nano /etc/nginx/nginx.conf include /etc/nginx/sites-enabled/*.conf Dadurch sollte die Konfigurationdatei ungefähr so aussehen: .. code-block:: bash user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*.conf; } Nun ist erfolgreich eine Reverse Proxy Konfiguration mit SSL Verschlüsselung erstellt. Die NGINX Konfigurationsdatei ist zusätzlich unter `Gitea/nginx.conf` abgelegt. Uncomplicated Firewall (UFW) ============================ UFW ist nützlich für die Verwaltung von Firewall-Regeln auf Linux-Systemen. Es handlet sich um eine einfache Schnittstelle, um Netzwerkverbindungen auf unserem System zu steuern und Zugriffe auf Dienste entweder zu ermöglichen oder zu blockieren. Verwaltung von IPTables: ------------------------ UFW verwaltet IPTables im Hintergrund, indem es eine vereinfachte Benutzeroberfläche bereitstellt, um Regeln zu erstellen, zu ändern und zu löschen. IPTables ist ein leistungsstarkes Framework für das Filtern und Weiterleiten von Netzwerkdaten in Linux. UFW ermöglicht es Benutzern, IPTables-Regeln zu erstellen, ohne sich mit der komplexen Syntax von IPTables befassen zu müssen. Default-Optionen: ----------------- Default Deny Incoming (Standardmäßig eingehenden Datenverkehr ablehnen): Diese Option blockiert jeglichen eingehenden Datenverkehr, der nicht explizit erlaubt ist. Dadurch wird das System vor unautorisiertem Zugriff von außen geschützt. Default Allow Outgoing (Standardmäßig ausgehenden Datenverkehr zulassen): Diese Option erlaubt standardmäßig allen ausgehenden Datenverkehr, was sicherstellt, dass Anwendungen auf dem System problemlos auf externe Ressourcen zugreifen können. Bedienung von UFW: ------------------ Hier sind einige grundlegende Befehle, um UFW zu verwenden: - **UFW aktivieren:** sudo ufw enable - **UFW deaktivieren:** sudo ufw disable - **Regel hinzufügen:** sudo ufw allow [Port/Protokoll] - **Regel entfernen:** sudo ufw delete [Nummer der Regel] - **Status anzeigen:** sudo ufw status verbose Aufsetzen UFW: .............. - **sudo ufw allow 80/tcp** - erlaubt eingehende TCP-Verbindungen auf Port 80, dem Standardport für HTTP-Verbindungen - **sudo ufw allow 443/tcp** - gestatten wir eingehenden TCP-Verkehr auf Port 443, dem Standardport für HTTPS-Verbindungen - **sudo ufw allow ssh bzw. sudo ufw allow 22/tcp** - erlauben eingehende SSH-Verbindungen auf Port 22, dem Standard-Port für SSH (Secure Shell) - **sudo ufw allow 22/udp** - erlaubt eingehenden UDP-Verkehr auf Port 22 Das vollständige reproduzierbare Script für die Umsetzung von UFW findet sich in `Gitea/ufw.sh`. Traefik ------- Zur Demonstration der Einfachheit von Traefik wurde eine alternative Konfiguration für die Gitea-Instanz erstellt. Traefik ist ein moderner Reverse-Proxy und Load-Balancer, der speziell für Container-Umgebungen entwickelt wurde. Die folgende YAML zeigt die Konfiguration von Traefik in Docker Compose: .. code-block:: yaml traefik: image: "traefik:v2" container_name: "traefik" command: #- "--log.level=DEBUG" #- "--api.insecure=true" - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=web" - "--entrypoints.web.address=:80" - "--entrypoints.web.http.redirections.entryPoint.to=websecure" - "--entrypoints.websecure.address=:443" - "--entrypoints.websecure.http.middlewares=https_config@docker,www-redirect@docker" - "--entrypoints.websecure.http.tls.options=default" - "--entrypoints.websecure.http.tls.certresolver=myresolver" - "--certificatesresolvers.myresolver.acme.tlschallenge=true" #- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" - "--certificatesresolvers.myresolver.acme.email=mahartma@mahartma.com" - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" labels: traefik.enable: true # https redirect traefik.http.middlewares.https_config.redirectscheme.scheme: "https" traefik.http.middlewares.https_config.redirectscheme.permanent: true # www -> non-www traefik.http.middlewares.www-redirect.redirectregex.regex: "^https://www.(.*)" traefik.http.middlewares.www-redirect.redirectregex.replacement: "https://$${1}" traefik.http.middlewares.www-redirect.redirectregex.permanent: true # basic-auth # Note: when used in docker-compose.yml all dollar signs in the hash need to be doubled for escaping. # echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g traefik.http.middlewares.dev-auth.basicauth.users: "username:TODO" # dashboard traefik.http.routers.api.rule: Host(`traefik.dva.mahart.ma`) traefik.http.routers.api.service: api@internal traefik.http.routers.api.middlewares: dev-auth traefik.http.routers.api.entrypoints: websecure com.centurylinklabs.watchtower.enable: true ports: - "443:443" - "80:80" volumes: - "/var/lib/traefik/letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock:ro" networks: - gitea - default restart: unless-stopped Beachtlich ist, dass diese Docker-Compose Definition alle Features abdeckt, die vorher über NGINX konfiguriert wurden. Traefik bietet also eine einfache und effiziente Möglichkeit, Reverse-Proxy- und Load-Balancer-Funktionalitäten in Container-Umgebungen bereitzustellen. Die Konfiguration bietet zusätzlich die Möglichkeit für basic auth und ein Dashboard für das Monitoring von Traefik. Die Docker-Compose Definition ist unter `Gitea/docker-compose-traefik.yml` abgelegt. Watchtower ---------- Was ist Watchtower? ``````````````````` Watchtower ist ein Open-Source-Projekt, das entwickelt wurde, um Docker-Container automatisch zu überwachen und zu aktualisieren. Es überwacht laufende Container auf dem System und überprüft regelmäßig, ob neue Versionen der Images verfügbar sind. Wenn eine neue Version gefunden wird, aktualisiert Watchtower automatisch den entsprechenden Container, ohne dass manuelle Eingriffe erforderlich sind. Installation und Verwendung ``````````````````````````` Die installation von Watchtower kann einfach als Docker realisierbar. Ein schneller Start ist mit folgenden Befehl möglich: .. code-block:: bash docker run -d \ --name watchtower \ -v /var/run/docker.sock:/var/run/docker.sock \ containrrr/watchtower Dieser Befehl startet den Watchtower-Container im Hintergrund und bindet an den Docker-Socket an das entsprechende Verzeichnis im Container, um auf die Docker-API Zugriff zu erhalten. In unserem Fall verwenden wir eine docker-compose.yml, um die Anwendung mit Parametern zu erweitern: .. code-block:: yaml version: "3" services: watchtower: image: containrrr/watchtower container_name: watchtower restart: unless-stopped volumes: - /var/run/docker.sock:/var/run/docker.sock command: --label-enable --interval=43200 --cleanup environment: WATCHTOWER_NOTIFICATIONS: email WATCHTOWER_NOTIFICATION_EMAIL_FROM: notifications@mail.net WATCHTOWER_NOTIFICATION_EMAIL_TO: ops@mail.com WATCHTOWER_NOTIFICATION_EMAIL_SERVER: mail.server.biz WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER: notifications@mail.net WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT: 587 WATCHTOWER_NOTIFICATION_EMAIL_SUBJECTTAG: web1 WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD: TODO dieser kann mit folgendem command gestartet werden: .. code-block:: bash docker-compose up -d Zur Konfiguration von Watchtower können Labels verwendet werden, um das Verhalten des Containers zu steuern. Folgendes Label aktiviert Auto-Updates für einen Container und muss lediglich an den Container angehängt werden: .. code-block:: docker labels: - "com.centurylinklabs.watchtower.enable=true" Major und Minor Updates werden abhängig von der Konfiguration automatisch installiert. Wenn der Container auf Version 2 läuft, werden die Minor-Versionen (2.1, 2.2, 2.3 usw.) automatisch installiert. Wenn der Container auf Version 2.1 läuft, werden die Patch-Versionen (2.1.1, 2.1.2, 2.1.3 usw.) automatisch installiert. Folgerung ````````` Watchtower ist ein äußerst nützliches Werkzeug zur Automatisierung von Docker-Container-Aktualisierungen. Die nahtlose Integration in bestehende Infrastruktur macht es zu einer attraktiven option, Automatisierung für Docker umzusetzen. Durch die Nutzung von Watchtower können Administratoren sicherstellen, dass ihre Docker-Container immer auf dem neuestem Stand sind, ohne dass ein manuelles Eingreifen erforderlich ist. Insgesamt ist Watchtower eine wertvolle Ergänzung für jede Docker-Umgebung, um die wiederkehrende Aufgabe von Container-Updates erledigen zu lassen.